<?php
class Solvex_Config
{
	/**
	 * Singleton instance
	 * 
	 * @var Solvex_Config
	 */
	protected static $_instance;
	
	/**
	 * Config data
	 * 
	 * @var Zend_Config
	 */
	protected $_data;
	
	/**
	 * Singleton instance accessor
	 * 
	 * @return Solvex_Config
	 */
	public static function getInstance()
	{
		if(null === self::$_instance){
			self::$_instance = new self();
		}
		return self::$_instance;
	}
	
	/**
	 * Constructor
	 */
	private function __construct()
	{
		$this->setData(new Zend_Config(array(), true));
		$this->loadData();
	}
	
	/**
	 * Load configuration data
	 * 
	 * @throws Solvex_Exception
	 */
	public function loadData()
	{
		// merge application options
		$options = Solvex::app()->getOptions();
		$this->mergeData($options);

		$clearCacheConfig = $this->getNode('system/cache/clear');
		if((bool) $clearCacheConfig->modules){
			if(Solvex::cache()->test('modules_config')){
				Solvex::cache()->remove('modules_config');
			}			
		}
		if((bool) $clearCacheConfig->database){
			if(Solvex::cache()->test('database_config')){
				Solvex::cache()->remove('database_config');
			}			
		}
		
		if(($data = Solvex::cache()->load('modules_config')) === false){
			$data = $this->_loadModulesConfig();			
			Solvex::cache()->save($data,'modules_config');
		}
		$this->mergeData($data);
		
		if(($data = Solvex::cache()->load('database_config')) === false){
			$data = $this->_loadDbConfig();			
			Solvex::cache()->save($data,'database_config');
		}
		$this->mergeData($data);
	}
	
	protected function _loadModulesConfig()
	{
		// merge modules config
		$config = new Zend_Config(array(), true);
		$modulesPackage = $this->getNode('system/package/modules');
		$path = APPLICATION_PATH . '/modules/' . $modulesPackage;
		try {
			$dir = new DirectoryIterator($path);
		} catch(Exception $e){
			throw new Solvex_Config_Exception("modules path is not readable");			
		}
		foreach($dir as $file){
			if($file->isDot() || !$file->isDir()){
				continue;
			}
			
			$module = $file->getFilename();
			
			if(Solvex_Tool_Filesystem::isSCCSDirectory($module)){
				continue;
			}
			
			$moduleConfigFile = $file->getPathname() . '/configs/module.xml';
			if(is_file($moduleConfigFile) && is_readable($moduleConfigFile)){
				$moduleConfig = new Zend_Config_Xml($moduleConfigFile,APPLICATION_ENV);
				$config->merge($moduleConfig);
			}
		}
		return $config;
	}
	
	protected function _loadDbConfig()
	{
		$configsTable = Solvex::table('config');
		$options = array(
			'pathKey' 	=> 'path',
			'valueKey'	=> 'value',
			'siteId'	=> Solvex::siteId()
		);
		$config = new Solvex_Config_Db($configsTable, $options);
		return $config;
	}
	
	/**
	 * Set config data
	 * @param Zend_Config $data
	 * @return Solvex_Config
	 */
	public function setData(Zend_Config $data)
	{
		$this->_data = $data;
		return $this;
	}
	
	/**
	 * Get config data
	 * 
	 * @return Zend_Config
	 */
	public function getData()
	{
		return $this->_data;
	}
	
	/**
	 * Fetch data by node
	 * 
	 * @param string $path
	 * @return string
	 */
	public function getNode($path)
	{
		$parts = explode('/', $path);
		$data  = $this->getData();
		
		foreach($parts as $part){
			$data = isset($data->{$part}) ? $data->{$part} : null;
		}
		
		return $data;
	}
	
	/**
	 * Merge configuration data
	 * 
	 * @param array|Zend_Config $data
	 * @throws Solvex_Exception
	 */
	public function mergeData($data)
	{
		if(is_array($data)){
			$data = new Zend_Config($data);
		} elseif(!$data instanceof Zend_Config){
			throw new Solvex_Exception("Cannot merge data unless is array or zend_config object");
		}
		$this->getData()->merge($data);
		return true;
	}
		
}